home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / pcmagazi / 1989 / 21 / dcompres.asm < prev    next >
Assembly Source File  |  1989-10-31  |  31KB  |  1,493 lines

  1. .MODEL    small
  2. cseg    segment para    public 'CODE'
  3. assume    cs:cseg
  4. ;;;;;;;;;;;;;;;;;
  5. ;;
  6. ;;    DCOMPRES - Keeps track of last access time and date for a file,
  7. ;;                 decompresses already compressed files when accessed
  8. ;;    Copyright (c) 1989 by Ziff Communications Co.
  9. ;;    Program by Ross M. Greenberg
  10. ;;;;;;;;;;;;;;;;;
  11.  
  12.  
  13. org    100h
  14.  
  15. TRUE        equ    1
  16. FALSE        equ    0
  17. NULL        equ    0
  18.  
  19. CR    equ    0dh
  20. LF    equ    0ah
  21. BELL    equ    07h
  22.  
  23. start:
  24.     jmp    install                ; It's traditional!
  25.  
  26. MAX_FILES    equ    100            ; max files in index
  27. FN_SIZE        equ    14            ; filename + dot + extension
  28. MAX_FN_SIZE    equ    64 + FN_SIZE        ; and the maximum path
  29.  
  30. ;;;;;;;;;;;;;;;;;
  31. ;; this structure should be an even number of bytes or contortions in C will
  32. ;; occur
  33. ;;;;;;;;;;;;;;;;
  34. file    struc
  35.     filename_len    dw    0
  36.     filename    db    FN_SIZE    dup (0)
  37.     left_ptr    dw    0
  38.     right_ptr    dw    0
  39.     date        dw    2    dup (0)
  40.     time        dw    2    dup (0)
  41.     status        db    0    ;normal = 0, compressed = 1 , del = 2
  42.     access_cnt    db    0    ; extra byte. Why not?
  43. file    ends
  44.  
  45. BUF_SIZE    equ    size file * MAX_FILES
  46.  
  47. NORMAL        equ    0
  48. COMPRESSED    equ    1
  49. DELETED        equ    2
  50.  
  51.  
  52. num_files    dw    0        ;don't separate these three!!!
  53. dir_name2    db    MAX_FN_SIZE    dup(0)
  54. buffer        db    BUF_SIZE    dup(0)
  55.  
  56. tag        db    0cdh, 020h, 'PCOMPRES'    ; don't separate these two
  57. TAG_LEN        equ    $ - tag
  58. file_out    db    'PCOMPRES.$$$', 0     ; or these two
  59. FILE_OUT_LEN    equ    $ - file_out
  60. index_name    db    'INDEX.CMP',0        ; don;t separate these two
  61. INDEX_NAME_LEN    equ    $ - index_name
  62.  
  63.  
  64. dir_name    db    MAX_FN_SIZE    dup(0)
  65. dir_name3    db    MAX_FN_SIZE    dup(0)
  66. dir_name4    db    MAX_FN_SIZE    dup(0)
  67. file_name    db    FN_SIZE        dup(0)
  68. tmp_buffer    db    MAX_FN_SIZE    dup(0)
  69. tmp_buf2    db    FN_SIZE        dup(0)
  70. dos_handle    dw    0
  71. in_handle    dw    0
  72. was_compressed    dw    0
  73. tmp_len        dw    0
  74. my_psp        dw    0
  75. users_psp    dw    0
  76. index_handle    dw    0
  77. file_seg    dw    0
  78. file_off    dw    0
  79. dirty_bit    dw    0
  80. in_use        dw    0
  81. switch_off    dw    0
  82. last_dos    dw    0
  83. old_dx        dw    0
  84. ignore_status    dw    0
  85. attributes    dw    1
  86. old_attrb    dw    0
  87. tag_buf        db    TAG_LEN    dup    (0)
  88.  
  89. table    struc
  90.     cmp_code    dw    0
  91.     suffix        db    0
  92. table    ends
  93.  
  94. MAX_CODE    equ    4096
  95. RESET_TABLE    equ    (MAX_CODE - 1)
  96.  
  97. codes    db    (MAX_CODE * size table)    dup (0)
  98. which_code    dw    0
  99.     
  100. codes_used    dw    0
  101.  
  102. stack        db    MAX_CODE    dup    (0)
  103. s_ptr        dw    stack
  104.  
  105. INBUF_SIZE    equ    3000
  106. in_buffer    db    INBUF_SIZE    dup    (0)
  107. out_buf        db    INBUF_SIZE    dup    (0)
  108. out_handle    dw    0
  109. out_cnt        dw    0
  110. buff_cnt    dw    0
  111. buff_size    dw    0
  112. tmp        db    0
  113. hold        dw    0
  114. old_code    dw    0
  115. last_char    db    0
  116. incode        dw    0
  117.  
  118. screen_msg    db    'Decompressing File...Standby'
  119. SCREEN_LEN    equ    ($ - screen_msg)
  120. screen_attrb    db    SCREEN_LEN dup(09fh);
  121. screen_segment    dw    0b800h
  122. SCREEN_OFFSET    equ    2 * ((12 * 80) + (40 - SCREEN_LEN/2))
  123.  
  124.  
  125. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  126. ;; Function 6c -- new to DOS 4.x is a pain.  All other functions operating
  127. ;; on files have consistent usage of ds:dx for the pointer to the file name.
  128. ;; Not this puppy.  Dile name is in ds:si.  Makes more sense, but it isn't
  129. ;; consistant.  This kludge makes it *look* consistent
  130. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  131.  
  132. set_6c:    cmp    byte ptr cs:[last_dos + 1], 06ch
  133.     jnz    not_6c1
  134.     mov    cs:[old_dx], dx
  135.     mov    dx, si
  136. not_6c1:
  137.     ret
  138.  
  139. ;;;;;;;;;;;;;;;;;;;;;;;;
  140. ;; The reverse of the above
  141. ;;;;;;;;;;;;;;;;;;;;;;;;
  142. reset_6c:    cmp    byte ptr cs:[last_dos + 1], 06ch
  143.     jnz    not_6c2
  144.     mov    dx, cs:[old_dx]
  145. not_6c2:
  146.     ret
  147.  
  148. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  149. ;;  Routine called by PCMANAGE to turn on and off the COMPRES program,
  150. ;;  dump out and read back in the file (if one is on memory)
  151. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  152. set_flag:
  153.     push    ds
  154.     push    cs
  155.     pop    ds
  156.  
  157.     mov    [switch_off], dx
  158.     mov    bx, [index_handle]        ; close file on change
  159.     cmp    bx, 0                ; first time?
  160.     jz    not_yet                ; yes
  161.  
  162.     inc    [in_use]
  163.     push    ax
  164.     push    bx
  165.  
  166.     mov    ah, 051h
  167.     int    21h
  168.     mov    [users_psp], bx
  169.     mov    bx, [my_psp]
  170.     mov    ah, 050h
  171.     int    21h
  172.  
  173.     pop    bx
  174.     pop    ax
  175.     call    update_file
  176.     mov    ah, 03eh
  177.     int    21h
  178.  
  179.     push    cx
  180.     push    dx
  181.     mov    ax, 04301h
  182.     mov    dx, offset dir_name
  183.     mov    cx, [old_attrb]
  184.     int    21h
  185.     pop    dx
  186.     pop    cx
  187.  
  188.     mov    [dir_name], 0
  189.  
  190.     mov    bx, [users_psp]
  191.     mov    ah, 050h
  192.     int    21h
  193.     dec    [in_use]
  194.  
  195. not_yet:
  196.     pop    ds
  197.     ret
  198.  
  199.  
  200. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  201. ;; New Dos Interrupt Service Routine
  202. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  203.  
  204. old_dos    dw    0            ; first the offset
  205.     dw    0            ; then the segment
  206.  
  207. new_dos    proc    far
  208.     pushf                ; save current flags,
  209.     sti                ; and turn on ints
  210.  
  211.     cmp    ax, 0fedch        ; our installation call?
  212.     jnz    @F
  213.     mov    ax, 0cdefh        ; yes. Return the inverse
  214.     popf
  215.     iret
  216.  
  217. @@:    cmp    ah, 0dch        ; one of our calls to toggle?
  218.     jnz    @F            ; no
  219.     call    set_flag        ; yes.  Do it, and pass it on.
  220. @@:
  221.     cmp    cs:[in_use], TRUE    ; no recursion!
  222.     jz    @F
  223.     cmp    cs:[switch_off], TRUE    ; turned off?
  224.     jz    @F
  225.  
  226. ;;;;;;;;;;;;;;;;;;;;;;;;
  227. ;;  We care about any file access call.  If not a function we care about,
  228. ;;  simply call the original DOS
  229. ;;;;;;;;;;;;;;;;;;;;;;;;
  230.  
  231.     cmp    ah, 0fh
  232.     jz    open
  233. ;    cmp    ah, 013h
  234. ;    jz    delete
  235.     cmp    ah, 016h
  236.     jz    create
  237.     cmp    ah, 03ch
  238.     jz    h_create
  239.     cmp    ah, 03dh
  240.     jz    h_open
  241.     cmp    ah, 06ch
  242.     jz    h_open
  243. ;    cmp    ah, 041h
  244. ;    jz    n_delete
  245.     cmp    ah, 04bh
  246.     jnz    not_execute            ; kludge
  247.     jmp    execute
  248. not_execute:
  249.     cmp    ah, 05ah
  250.     jz    h_create
  251.     cmp    ah, 05bh
  252.     jz    h_create
  253.     
  254. @@:
  255.     popf
  256.     jmp    dword ptr cs:[old_dos]
  257.  
  258. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  259. ;; Process all the FCB calls
  260. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  261.  
  262. open:
  263. delete:
  264. create:
  265.     mov    cs:[last_dos], ax        ; save for re-execute later
  266.     mov    cs:[in_use], TRUE        ; no recursion!
  267.     call    dword ptr cs:[old_dos]        ; do the original call
  268.     pushf
  269.     jnc    op_good                ; if good continue
  270.     jmp    op_failed            ; else why bother?
  271.  
  272. op_good:
  273.     push    dx                ; translate FCB filenames into
  274.     push    ds                ; ASCIIZ filenames
  275.     call    fcb_stuff
  276.     push    ax
  277.     push    bx
  278.  
  279.     mov    ax, 03d00h            ; open with handle for the
  280.     int    21h                ; ioctl -- our psp
  281.     mov    cs:[dos_handle], ax
  282.     call    lookup                ; main function call
  283.     mov    bx, cs:[dos_handle]        ; close file in our psp
  284.     mov    ah, 03eh
  285.     int    21h
  286.     pop    bx
  287.     pop    ax
  288.  
  289.     pop    ds
  290.     pop    dx
  291.  
  292.     cmp    cs:[was_compressed], TRUE    ; must we play?
  293.     jnz    normal1                ; no, skip
  294.  
  295.                         ; yes, continue
  296. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  297. ;; first, close then delete the file using users fcb, then rename the tmp
  298. ;; file to the name in the fcb, then re-do the users operation
  299. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  300.     mov    cs:[was_compressed], FALSE
  301.     push    ax
  302.     mov    ah, 010h
  303.     int    21h                ; close the file
  304.     mov    ah, 013h
  305.     int    21h                ; delete it
  306.  
  307. ;;;;;;;;;;;;;;;
  308. ;; use handle rename. Filename in tmp_buffer still. Decompressed in temp file
  309. ;;;;;;;;;;;;;;;
  310.     call    rename
  311.  
  312.     mov    ax, cs:[last_dos]        ; reissue the call
  313.     int    21h
  314.  
  315.     pop    ax
  316.  
  317. normal1:
  318.     jmp    op_failed            ; common return
  319.  
  320. ;;;;;;;;;;;;;;;;;;;
  321. ;; Process all handle operations here....
  322. ;;;;;;;;;;;;;;;;;;;
  323. h_create:
  324. h_open:
  325. n_delete:
  326.     mov    cs:[last_dos], ax
  327.     mov    cs:[in_use], TRUE
  328.     call    dword ptr cs:[old_dos]        ; issue the users call.
  329.     pushf
  330.     sti
  331.     jc    op_failed            ; if it failed, simply return
  332.     mov    cs:[dos_handle], ax
  333.  
  334.     call    set_6c                ; kludge on 4.x 6c call
  335.  
  336.     call    lookup                ; main call, file is open
  337.  
  338.     call    reset_6c            ; reset from 4.x call
  339.  
  340.     cmp    cs:[was_compressed], TRUE    ; do anything unusual?
  341.     jnz    normal2                ; no
  342.  
  343. ;;;;;;;;;;;;;;;;;;
  344. ;;  Rename the file
  345. ;;;;;;;;;;;;;;;;;;
  346.  
  347.     push    ax
  348.     call    handle_stuff            ; do the rename
  349.     mov    ax, cs:[last_dos]        ; issue original call again
  350.     int    21h
  351.  
  352.     pop    ax
  353.  
  354. normal2:
  355. op_failed:
  356.     popf
  357.     mov    cs:[in_use], FALSE
  358.     ret    2
  359.  
  360. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  361. ;; Reset the compressed flag, close the file, delete it, rename it, return
  362. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  363.  
  364. handle_stuff proc near
  365.  
  366.     mov    cs:[was_compressed], FALSE
  367.  
  368.     push    bx
  369.     push    dx
  370.     push    ds
  371.  
  372.     mov    bx, cs:[dos_handle]
  373.     mov    ah, 03eh
  374.     int    21h
  375.     push    cs
  376.     pop    ds
  377.     mov    dx, offset cs:tmp_buffer
  378.     mov    ah, 041h
  379.     int    21h
  380.     call    rename
  381.  
  382.     pop    ds
  383.     pop    dx
  384.     pop    bx
  385.     ret
  386. handle_stuff    endp
  387.  
  388. ;;;;;;;;;;;;;;;;;;;;;
  389. ;; handles a little differently.  Obviously, the file must be decompressed
  390. ;; before the call...
  391. ;;;;;;;;;;;;;;;;;;;;;
  392. execute:
  393.     mov    cs:[in_use], TRUE
  394.  
  395.     push    ax
  396.     push    bx
  397.  
  398.     mov    ax, 03d00h            ; open with handle
  399.     int    21h
  400.     mov    cs:[dos_handle], ax
  401.  
  402.     call    lookup                ; main work
  403.  
  404.     mov    bx, cs:[dos_handle]        ; close file
  405.     mov    ah, 03eh
  406.     int    21h
  407.  
  408.     pop    bx
  409.     pop    ax
  410.  
  411.     cmp    cs:[was_compressed], TRUE    ; skip exciting stuff?
  412.     jnz    normal3                ; yes
  413.  
  414.     push    ax
  415.     call    handle_stuff            ; do the rename
  416.     pop    ax
  417.  
  418. normal3:
  419.     popf
  420.     mov    cs:[in_use], FALSE
  421.     jmp    dword ptr cs:[old_dos]        ; execute the program
  422.  
  423. new_dos    endp
  424.  
  425. ;;;;;;;;;;;;;;;;;;;;;;;;;
  426. ;;  This routine makes an FCB entry, extended or not, into a semi-qualified
  427. ;;  ASCIIZ filename
  428. ;;;;;;;;;;;;;;;;;;;;;;;;;
  429.  
  430. fcb_stuff    proc    near
  431.     push    ax
  432.     push    cx
  433.     push    si
  434.     push    di
  435.     push    es
  436.  
  437.     mov    si, dx
  438.     cmp    byte ptr ds:[si], 0ffh        ; extended FCB?
  439.     jnz    @F                ; normal
  440.     add    si, 7                ; point to the filename, 7
  441.                         ; bytes into extended FCB
  442. @@:    push    cs
  443.     pop    es
  444.     mov    di, offset cs:tmp_buf2        ; ASCIIZ buffer
  445.     cmp    byte ptr ds:[si], 0        ; default drive?
  446.     jz    @F                ; yes
  447.     mov    al, ds:[si]            ; no. add drive to buffer
  448.     mov    es:[di], al
  449.     add    byte ptr es:[di], 'A' - 1
  450.     mov    byte ptr es:[di + 1], ':'
  451.     add    di, 2                ; to filename position
  452.  
  453. @@:    inc    si                ; and bypass the drive in FCB
  454.  
  455.     mov    cx, 11                ; filename(8) + extension(3)
  456.                         ; always left justified, space
  457.                         ; filled
  458. file_lp:
  459.     mov    al, ds:[si]
  460.     cmp    al, ' '                ; space?
  461.     jz    @F                ; yes, so skip it
  462.     mov    es:[di], al            ; no, stuff the character
  463.     inc    di
  464.  
  465. @@:    cmp    cx, 4                ; at start of extension?
  466.     jnz    @F
  467.     mov    byte ptr es:[di], '.'        ; yes. stuff a dot
  468.     inc    di
  469.  
  470. @@:    inc    si
  471.     loop    file_lp                ; for entire filename
  472.     mov    byte ptr es:[di], 0        ; zero the end byte
  473.  
  474.     pop    es
  475.     pop    di
  476.     pop    si
  477.     pop    cx
  478.     pop    ax
  479.  
  480.     push    cs
  481.     pop    ds
  482.     mov    dx, offset tmp_buf2        ; point to the ASCIIZ filename
  483.  
  484.     ret
  485.  
  486. fcb_stuff    endp
  487.  
  488. ;;;;;;;;;;;;;;;;;;;;;;;
  489. ;; Main routine.
  490. ;;
  491. ;; 1.  Determine if a file or device.  If device, return.
  492. ;; 2.  Determine if fixed disk. If not, return
  493. ;; 3.  Fully qualify file/pathname with undocumented AH=60h call
  494. ;; 4.  Save users PSP, reset with our own.  Handle table in users might be
  495. ;;     full...
  496. ;; 5.  Scan path name, isolate last '\' (separates path from filename)
  497. ;;     saving the length of the path.
  498. ;; 6.  Save the path in one location, the filename in another
  499. ;; 7.  Stuff the name of the index file to the tail of the path
  500. ;; 8.  Determine if this is the same index filepath as already loaded
  501. ;; 9.  If not, write file if needed.
  502. ;;10.  Load new file.  If not there, create one -- and dummy the file out.
  503. ;;11.  Reset to the beginning of the binary tree index
  504. ;;12.  Find the file in index.  If found, then goto 14
  505. ;;13.  File not in index. If room, add it and return:  file has not been
  506. ;;     compressed, obviously.  New entry updated with current date and time.
  507. ;;14.  If file not compressed, merely update date and time and return.
  508. ;;15.  If file is compressed, check to make sure it is, then decompress it
  509. ;;     into temporary file named PCOMPRESS.$$$ and return
  510. ;;16.  If, upon examination file is not a compressed one, reset to normal
  511. ;;     status
  512. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  513.  
  514. lookup:
  515.     mov    cs:[was_compressed], FALSE
  516.  
  517.     cld
  518.     push    ax
  519.     push    bx
  520.     push    cx
  521.     push    dx
  522.     push    si
  523.     push    di
  524.     push    ds
  525.     push    es
  526.  
  527.  
  528.     push    dx
  529.     mov    ax, 04400h            ; ioctl call returns status
  530.     mov    bx, cs:[dos_handle]        ; in the dx register
  531.     mov    cx, 2
  532.     xor    dx, dx
  533.     int    21h
  534.     test    dx, 080h            ; devices have high bit set
  535.     pop    dx
  536.  
  537.     jz    @F                ; not set, a file
  538.     jmp    done2                ; is a character device
  539.     
  540. @@:    push    cs                ; a regular file
  541.     pop    es
  542.     mov    si, dx
  543.     mov    di, offset tmp_buffer
  544.     mov    ah, 60h                ; undocumented DOS call to
  545.     int    21h                ; fully qualify a file/path
  546.                         ; knows about SUBST and ASSIGN
  547.  
  548.     mov    dl, es:[di]            ; get the disk letter
  549.     sub    dl, 'A' - 1            ; A=1, B=2, etc...
  550.     mov    ah, 1ch                ; get disk parameters
  551.     int    21h
  552.     cmp    byte ptr [bx], 0f8h        ; on return, DS:BX points to
  553.     jz    @F                ; first FAT entry. F8 is fixed
  554.     jmp    done2                ; disk. Anything else, we skip
  555.  
  556. @@:    mov    ah, 051h            ; get users PSP, save
  557.     int    21h                ; then swap our's in.
  558.     mov    cs:[users_psp], bx
  559.     mov    bx, cs:[my_psp]
  560.     mov    ah, 050h
  561.     int    21h
  562.  
  563. ;;;;;;;;;;;;;;;;;
  564. ;; separate the path from the filename into two buffers.
  565. ;;;;;;;;;;;;;;;;;
  566.  
  567.     xor    cx, cx
  568. end_path:
  569.     mov    al, es:[di]
  570.     cmp    al, 0            ; end of path? (ASCIIZ)
  571.     jz    @F            ; yes
  572.     inc    cx
  573.     inc    di
  574.     cmp    al, '\'            ; path delimiter?
  575.     jnz    end_path
  576.     mov    cs:[tmp_len], cx    ; save length
  577.     jmp    end_path
  578.  
  579. @@:    push    cs            ; create path to filename
  580.     pop    ds
  581.     mov    si, offset cs:[tmp_buffer]
  582.     mov    di, offset cs:[dir_name]
  583.     mov    cx, cs:[tmp_len]
  584.  
  585.     cld
  586. @@:    movsb                    ; move the path over
  587.     loop    @B
  588.  
  589. ;;;;;;;;;;;;;;;;
  590. ;;  Stuff index name onto path
  591. ;;;;;;;;;;;;;;;;
  592.  
  593.     mov    si, offset cs:[index_name]
  594.     mov    cx, INDEX_NAME_LEN
  595.     cld
  596. @@:    movsb
  597.     loop    @B
  598.  
  599. ;;;;;;;;;;;;;;;;
  600. ;;  Stuff temporary filename onto path
  601. ;;;;;;;;;;;;;;;;
  602.     mov    si, offset cs:[tmp_buffer]
  603.     mov    di, offset cs:[dir_name3]
  604.     mov    cx, cs:[tmp_len]
  605.  
  606.     cld
  607. @@:    movsb                    ; move the path over
  608.     loop    @B
  609.  
  610.  
  611.     mov    si, offset cs:[file_out]
  612.     mov    cx, FILE_OUT_LEN
  613.     cld
  614. @@:    movsb
  615.     loop    @B
  616.  
  617. ;;;;;;;;;;;;;;;;;;;;;;;;
  618. ;;  Same index name as last time?
  619. ;;;;;;;;;;;;;;;;;;;;;;;;
  620.  
  621.     mov    si, offset cs:[dir_name]
  622.     mov    di, offset cs:[dir_name2]
  623.     mov    cx, cs:[tmp_len]
  624.     cld
  625.     repz    cmpsb                ; pop out on no match
  626.     cmp    byte ptr cs:[di], 'I'        ;first letter of "INDEX.CMP"
  627.     jnz    @F                ; not a match
  628.     cmp    cx, 0                ; all through and a match?
  629.     jnz    @F
  630.     jmp    a_match                ; yes
  631.                         ; no match, fall through
  632.  
  633. ;;;;;;;;;;;;;;;;;;;;;
  634. ;;  New index file.  Close the old one first, then create a new one
  635. ;;  if needed with blank entries.
  636. ;;;;;;;;;;;;;;;;;;;;;
  637.  
  638. index_open:
  639. @@:    mov    bx, [index_handle]        ; close file on change
  640.     cmp    bx, 0                ; first time?
  641.     jz    @F                ; yes
  642.     call    update_file            ; update the old file and
  643.     mov    ah, 03eh            ; do the close
  644.     int    21h
  645.  
  646. reset_attrb:
  647.     push    cx
  648.     mov    ax, 04301h
  649.     mov    dx, offset dir_name2
  650.     mov    cx, [old_attrb]
  651.     int    21h
  652.     pop    cx
  653.  
  654.  
  655. @@:    mov    ax, 04300h            ; save the current attributes
  656.     mov    dx, offset dir_name
  657.     int    21h
  658.     jc    no_file
  659.     mov    [old_attrb], cx
  660.  
  661.     mov    ax, 04301h            ; make it readable
  662.     mov    dx, offset dir_name
  663.     mov    cx, 0
  664.     int    21h
  665.  
  666.     mov    ax, 3d02h            ; open the new file up
  667.     mov    dx, offset dir_name
  668.     int    21h
  669.     jc    no_file                ; no file. Create one.
  670.  
  671.     mov    cs:[index_handle], ax
  672.     mov    bx, ax
  673.  
  674.     mov    cs:[num_files], 0        ;; ??
  675.     mov    cx, size num_files + BUF_SIZE + MAX_FN_SIZE
  676.     mov    dx, offset cs:[num_files]    ; buffer to read into
  677.     mov    ah, 03fh
  678.     int    21h
  679.     jnc    a_match                ; read okay!
  680.  
  681. no_file:
  682.     mov    ah, 03ch            ; create a new file
  683.     mov    dx, offset cs:dir_name
  684.     mov    cx, 0
  685.     int    21h
  686.  
  687.     push    cs:[attributes]            ; mov attributes as if old file
  688.     pop    cs:[old_attrb]
  689.  
  690.     jnc    @F
  691.     jmp    done                ;problem
  692.  
  693.  
  694. ;;;;;;;;;;;;;
  695. ;; Zero out what will be the contents of the new file
  696. ;;;;;;;;;;;;;
  697. @@:    mov    bx, ax
  698.     mov    cs:[index_handle], ax
  699.  
  700.     mov    cx, size num_files + BUF_SIZE + MAX_FN_SIZE
  701.                         ; Zero out buffer
  702.     mov    di, offset cs:num_files
  703. @@:    mov    byte ptr cs:[di], 0
  704.     inc    di
  705.     loop    @B
  706.  
  707.     mov    si, offset cs:[dir_name]    ; but load index file name
  708.     mov    di, offset cs:[dir_name2]
  709.     mov    cx, cs:[tmp_len]
  710.     add    cx, INDEX_NAME_LEN
  711.  
  712.     cld
  713. @@:    movsb
  714.     loop    @B
  715.  
  716. ;;;;;;;;;;;;;;;;;;;
  717. ;; write out with zero files, index filename, an empty buffer
  718. ;;;;;;;;;;;;;;;;;;;
  719.     mov    cx, BUF_SIZE + size num_files + MAX_FN_SIZE
  720.     mov    dx, offset cs:num_files
  721.     mov    ah, 040h
  722.     int    21h
  723.     call    commit                ; make sure it gets written
  724.  
  725. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  726. ;;    At this point, the index is loaded into memory. Find the file
  727. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  728.  
  729. a_match:
  730.     mov    si, offset cs:[tmp_buffer]
  731.     add    si, cs:[tmp_len]            ;pointer to filename
  732.     mov    di, offset cs:[file_name]
  733.     mov    cs:[file_seg], es
  734.     mov    cs:[file_off], di
  735.  
  736. @@:    mov    al, ds:[si]                ; move filename again
  737.     mov    es:[di], al
  738.     inc    di
  739.     inc    si
  740.     cmp    al, 0
  741.     jnz    @B
  742.  
  743.     push    cs
  744.     pop    ds
  745.  
  746.     mov    ax, 1                ; get first one
  747.     call    get_pointer            ; bx gets pointer to entry
  748.  
  749. look_lp:
  750.     mov    ds, cs:[file_seg]        ; source seg
  751.     push    cs
  752.     pop    es                ; target seg - the buffer
  753.  
  754.     mov    si, cs:[file_off]        ; get back the filename
  755.     mov    di, bx
  756.     add    di, filename            ; and point to it in record
  757.     mov    cx, word ptr cs:[bx].filename_len    
  758.     cmp    cx, 0
  759.     jz    no_match            ; if empty record
  760.  
  761. @@:    mov    al, ds:[si]
  762.     cmp    al, es:[di]
  763.     jnz    no_match            ; try again
  764.     inc    si
  765.     inc    di
  766.     loop    @B
  767.  
  768.     inc    cs:[dirty_bit]            ; found it!
  769.     call    update                ; a match.  Update it.
  770.     jmp    done
  771.  
  772.                         
  773. done:
  774.     mov    bx, cs:[users_psp]        ;reset users PSP and return
  775.     mov    ah, 050h
  776.     int    21h
  777. done2:
  778.     pop    es
  779.     pop    ds
  780.     pop    di
  781.     pop    si
  782.     pop    dx
  783.     pop    cx
  784.     pop    bx
  785.     pop    ax
  786.     ret
  787.  
  788. ;;;;;;;;;;;;;;;
  789. ;; Current entry isn't what we want.  Try next one.
  790. ;;;;;;;;;;;;;;;
  791.  
  792. no_match:
  793.     push    cs
  794.     pop    ds
  795.     mov    ax, [bx].left_ptr    ; assume less than
  796.     mov    dx, left_ptr
  797.     jl    @F
  798.     mov    ax, [bx].right_ptr    ; greater than, use right pointer
  799.     mov    dx, right_ptr
  800. @@:    cmp    ax, 0            ; end of the line?
  801.     jz    @F            ; yes
  802.     call    get_pointer        ; bx points to next entry
  803.     jmp    look_lp            ; se if a match
  804.  
  805. ;;;;;;;;;;
  806. ;; insert routine
  807. ;;;;;;;;;;
  808. @@:    cmp    cs:[num_files], MAX_FILES    ; full already?
  809.     jnz    @F            ; no
  810.     jmp    done            ; yes.  Ignore it.
  811. @@:    inc    cs:[num_files]        ; increase the count
  812.     mov    ax, cs:[num_files]
  813.     add    bx, dx            ; left or right pointer offset
  814.     mov    cs:[bx], ax
  815.     inc    cs:[dirty_bit]
  816.     call    get_pointer        ; point to empty record
  817.  
  818. ;;;;;;;;;;;;;;;;;;
  819. ;; copy the name into the buffer
  820. ;;;;;;;;;;;;;;;;;;
  821.     mov    ds, cs:[file_seg]    ; source seg
  822.     push    cs
  823.     pop    es            ; target seg - the buffer
  824.  
  825.     mov    si, cs:[file_off]    ; get back the filename
  826.     mov    di, bx
  827.     add    di, filename
  828.     xor    cx, cx
  829.     cld
  830. @@:    movsb
  831.     inc    cx
  832.     cmp    byte ptr ds:[si], 0
  833.     jnz    @B
  834. ;;;;;;;;;;;;;;;;
  835. ;; set up the rest of the entry
  836. ;;;;;;;;;;;;;;;;
  837.  
  838.     mov    byte ptr es:[di], 0        ; trailing null: nice for 'C'
  839.     mov    cs:[bx].filename_len, cx
  840.     mov    cs:[bx].left_ptr, 0
  841.     mov    cs:[bx].right_ptr, 0
  842.     mov    cs:[bx].access_cnt, 1
  843.     mov    cs:[bx].status, NORMAL
  844.     inc    cs:[dirty_bit]
  845.  
  846.     call    update                ; add date and time
  847.     jmp    done
  848.  
  849. ;;;;;;;;;;;;;;;;;;;;;
  850. ;;  Returns bx as in  bx = (ax * size entry) + buffer offset
  851. ;;  ax is the entry we seek
  852. ;;;;;;;;;;;;;;;;;;;;
  853.  
  854.  
  855. get_pointer    proc    near
  856.     push    cx
  857.     push    dx
  858.  
  859.     dec    ax
  860.     mov    bx, ax
  861.     mov    cx, size file
  862.     mul    cx
  863.     xchg    ax, bx
  864.     add    bx, offset cs:[buffer]
  865.  
  866.     pop    dx
  867.     pop    cx
  868.     ret
  869. get_pointer    endp
  870.  
  871. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  872. ;;  Write all the stuff in the current buffer out to disk
  873. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  874. update_file    proc    near
  875.     push    ax
  876.     push    bx
  877.     push    cx
  878.     push    dx
  879.     push    ds
  880.  
  881.     push    cs
  882.     pop    ds
  883.  
  884.  
  885.     mov    cs:[dirty_bit], 0        ; now we're clean
  886.  
  887.     xor    cx, cx                ; lseek to beginning
  888.     xor    dx, dx
  889.     mov    ax, 04200h
  890.     mov    bx, cs:[index_handle]
  891.     int    21h
  892.  
  893.     mov    dx, offset num_files         ; write it
  894.     mov    cx, BUF_SIZE + size num_files + MAX_FN_SIZE
  895.     mov    ah, 040h
  896.     int    21h
  897.  
  898.     call    commit                ; make sure it's written
  899.  
  900.     pop    ds
  901.     pop    dx
  902.     pop    cx
  903.     pop    bx
  904.     pop    ax
  905.     ret
  906. update_file    endp
  907.  
  908. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  909. ;; Add date and time.  If compressed, decompress.
  910. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  911.  
  912. update:
  913.     mov    ah, 02ah        ; get the date
  914.     int    21h
  915.     mov    cs:[bx].date, cx
  916.     mov    cs:[bx].date + 2, dx
  917.     mov    ah, 02ch        ; get the time
  918.     int    21h
  919.     mov    cs:[bx].time, cx    ; stuff them
  920.     mov    cs:[bx].time + 2, dx
  921.     inc    cs:[bx].access_cnt    ; up the access count
  922.     cmp    cs:[ignore_status], TRUE
  923.     jz    do_it_anyway
  924.     cmp    cs:[bx].status, COMPRESSED
  925.     jnz    @F            ; normal
  926. do_it_anyway:
  927.     push    bx            ; save the entry pointer
  928.     call    decompress        ; expand the file
  929.     pop    bx
  930.     mov    cs:[bx].status, NORMAL    ; reset the status
  931.     inc    cs:[dirty_bit]        ; we have to write now.
  932. @@:    ret
  933.  
  934. ;;;;;;;;;;;;;;;;;;;;;;;;
  935. ;;  Is it really compressed?
  936. ;;;;;;;;;;;;;;;;;;;;;;;;
  937. decompress:
  938.     push    ax
  939.     push    bx
  940.     push    cx
  941.     push    dx
  942.     push    di
  943.     push    si
  944.  
  945. ;;;;;;;;;;;;
  946. ;; Read the first few bytes, see if it matches our unique entry
  947. ;;;;;;;;;;;;
  948.     mov    dx, offset cs:tmp_buffer
  949.     add    dx, filename
  950.     mov    ax, 3d00h
  951.     int    21h
  952.     jc    bad_decom2        ; can't decompress if can't open!
  953.  
  954.     mov    cs:[in_handle], ax
  955.     mov    bx, ax
  956.     mov    cx, TAG_LEN         ; read the first coupla bytes in
  957.     mov    dx, offset cs:tag_buf
  958.     mov    ah, 03fh
  959.     int    21h
  960.     jc    bad_decom        ; too short for one of ours!
  961.     cmp    ax, TAG_LEN
  962.     jl    bad_decom
  963.  
  964.     mov    si, offset cs:tag    ; our tag line?
  965.     mov    di, dx
  966.     mov    cx, TAG_LEN
  967. @@:    mov    al, byte ptr cs:[si]
  968.     cmp    al, byte ptr cs:[di]
  969.     jnz    bad_decom
  970.     loop    @B            ; a match?
  971.  
  972.     call    do_decomp        ; yes! Decompress it
  973.  
  974. bad_decom:
  975.     mov    bx, cs:[in_handle]    ; close the file
  976.     mov    ah, 03eh
  977.     int    21h
  978. bad_decom2:
  979.     cmp    cs:[bx].status, NORMAL    ; if it was normal, don't set dirty bit
  980.     jz    @F
  981.     mov    cs:[dirty_bit], TRUE
  982.  
  983. @@:    pop    si
  984.     pop    di
  985.     pop    dx
  986.     pop    cx
  987.     pop    bx
  988.     pop    ax
  989.  
  990.     ret
  991.  
  992. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  993. ;;  Open a duplicate handle on the file, then close the duplicate handle.
  994. ;;  This causes brain damaged dos to commit the file, regardless of
  995. ;;  version
  996. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  997. commit    proc    near
  998.     push    ax
  999.     push    bx
  1000.     mov    ah, 045h
  1001.     mov    bx, cs:[index_handle]
  1002.     int    21h
  1003.     mov    bx, ax
  1004.     mov    ah, 03eh
  1005.     int    21h
  1006.     pop    bx
  1007.     pop    ax
  1008.     ret
  1009. commit    endp
  1010.  
  1011. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1012. ;;  LZW compression routines
  1013. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1014.  
  1015. ;;;;;;;;;;;;;;;;
  1016. ;; Zero out the table.
  1017. ;;;;;;;;;;;;;;;;
  1018.  
  1019. init_tab    proc    near
  1020.     push    ax
  1021.     push    cx
  1022.     push    si
  1023.     push    ds
  1024.  
  1025.     xor    ax, ax
  1026.     mov    cx, 256
  1027.     mov    si, offset cs:codes
  1028.     push    cs
  1029.     pop    ds
  1030. lp:
  1031.     mov    [si].cmp_code, 0
  1032.     mov    [si].suffix, al
  1033.     inc    al
  1034.     add    si, size table
  1035.     loop    lp
  1036.  
  1037.     mov    cs:[codes_used], 256
  1038.  
  1039.     pop    ds
  1040.     pop    si
  1041.     pop    cx
  1042.     pop    ax
  1043.     ret
  1044. init_tab    endp
  1045.  
  1046. ;;;;;;;;;;;;;;;;;;;;;
  1047. ;;  Actual decompression routine
  1048. ;;;;;;;;;;;;;;;;;;;;;
  1049.  
  1050. do_decomp    proc    near
  1051.  
  1052.     call     paint            ; XT owners don't think we crashed...
  1053.  
  1054.     call    init_tab
  1055.  
  1056.     mov    cs:[which_code], 0    ; initialize a bunch of variables
  1057.     mov    cs:[hold], 0
  1058.     mov    cs:[s_ptr], offset cs:stack    ; not a real stack
  1059.     mov    cs:[out_cnt], 0
  1060.     mov    cs:[buff_cnt], 0
  1061.     mov    cs:[buff_size], 0
  1062.     mov    cs:[tmp], 0
  1063.  
  1064.     push    cs
  1065.     pop    ds
  1066.  
  1067.     mov    dx, offset cs:dir_name3        ; create the temporary file
  1068.     xor    cx, cx
  1069.     mov    ah, 03ch
  1070.     int    21h
  1071.     mov    cs:[out_handle], ax
  1072.  
  1073.     call    get_code        ; read a code in
  1074.     mov    bl, al            ; save it
  1075.     call    stuff            ; stuff on the stack
  1076.     call    unstuff            ; unstuff into the output file
  1077.     mov    cs:[old_code], ax    ; save it
  1078.     mov    cs:[last_char], bl    ; save it
  1079. decode:
  1080.     call    get_code        ; loop. Get a code. expand it.
  1081.     jc    exit            ; we're done on carry
  1082.     cmp    ax, RESET_TABLE        ; table full in compressor?
  1083.     jnz    no_exit
  1084.  
  1085.     call    init_tab        ; yes. Reset everything
  1086.  
  1087.     call    get_code        ; and start over
  1088.     mov    bl, al
  1089.     call    stuff
  1090.     call    unstuff
  1091.     mov    cs:[old_code], ax
  1092.     jmp    decode            ; now we're back to normal
  1093.  
  1094. exit:
  1095.     call    output            ; exit. Force output of last code
  1096.     mov    bx, cs:[out_handle]
  1097.     mov    ah, 03eh
  1098.     int    21h            ; close decomp'ed temp file
  1099.  
  1100.     mov    cs:[was_compressed], TRUE
  1101.  
  1102.     call    paint            ; Yo! XT owner! Wake up!
  1103.     ret                ; good-run exit point
  1104.  
  1105. no_exit:
  1106.     mov    cs:[incode], ax        ; save the code
  1107.     cmp    ax, cs:[codes_used]    ; already in table?
  1108.     jl    @F            ; yes
  1109.  
  1110. ;;;;;;;;;;;;;;;;;;;;;;;;;
  1111. ;; Special class of codes for highly repetitive strings.  The code can
  1112. ;; be transmitted before it exists!  So, we simply add a new code
  1113. ;;;;;;;;;;;;;;;;;;;;;;;;;
  1114.     mov    ax, cs:[old_code]
  1115.     mov    bl, cs:[last_char]
  1116.     call    stuff
  1117.  
  1118. @@:    push    ax            ; save the code
  1119.     mov    cx, size table        ; get the suffix
  1120.     mul    cx
  1121.     mov    si, ax
  1122.     add    si, offset cs:codes
  1123.     pop    ax
  1124.     cmp    ax, 256            ; "low" code?
  1125.     jl    @F            ; yup. End loop
  1126.     mov    bl,cs:[si].suffix
  1127.     call    stuff            ; enter onto stack
  1128.     mov    ax, cs:[si].cmp_code    ; next code in code sequence
  1129.     jmp    @B            ; loop
  1130.  
  1131. @@:    mov    bl, cs:[si].suffix    ; do the last char
  1132.     mov    cs:[last_char], bl    ; and save it
  1133.     call    stuff            ; add to stack
  1134.     call    unstuff            ; write out whole stack
  1135.     
  1136.     cmp    cs:[codes_used], MAX_CODE    ; full table?
  1137.     jz    @F                ; yup
  1138.  
  1139. ;;;;;;;;;;;;;;;;;;;;
  1140. ;;  Add the code into the table
  1141. ;;;;;;;;;;;;;;;;;;;;;
  1142.     mov    ax, cs:[codes_used]
  1143.     mov    cx, size table
  1144.     mul    cx
  1145.     mov    si, ax
  1146.     add    si, offset cs:codes
  1147.     mov    ax, cs:[old_code]
  1148.     mov    cs:[si].cmp_code, ax
  1149.     mov    al, cs:[last_char]
  1150.     mov    cs:[si].suffix, al
  1151.     inc    cs:[codes_used]        ; up the number of codes used in table
  1152.  
  1153. @@:    mov    ax, cs:[incode]        ; save original code
  1154.     mov    cs:[old_code], ax
  1155.     jmp    decode            ; next!
  1156.  
  1157. do_decomp    endp
  1158.  
  1159. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1160. ;;  The codes are actually 12 bit entities:  a byte and a half.  So, take
  1161. ;;  turns reading two bytes, returning 12 bits, then one byte, returning
  1162. ;;  old half byte (a nibble) and new byte.  That's a code.  And it fits
  1163. ;;  within a register.  How nifty!
  1164. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1165. get_code:
  1166.     cmp    cs:[which_code], 0        ; even or odd code?
  1167.     jnz    odd_code
  1168.  
  1169.     call    get_byte            ; get the first byte
  1170.     jc    get_code_ret            ; eof
  1171.  
  1172.     xor    ax, ax
  1173.     mov    al, byte ptr cs:[tmp]        ; get byte 
  1174.     mov    cl, 4                ; and pop it down a nibble
  1175.     shl    ax, cl
  1176.  
  1177.     call    get_byte            ; get next byte
  1178.     jc    get_code_ret            ; eof
  1179.  
  1180.     mov    bx, ax                ; turn it into a code and save
  1181.     xor    ax, ax                ; left over nibble.
  1182.     mov    al, byte ptr cs:[tmp]
  1183.     mov    cs:[hold], ax
  1184.     and    cs:[hold], 0fh            ; set the leftover flag.
  1185.     mov    cl, 4
  1186.     shr    ax, cl
  1187.     or    ax, bx
  1188.     mov    cs:[which_code], 1
  1189.     clc
  1190.     jmp    get_code_ret
  1191.  
  1192. odd_code:
  1193.     mov    ax, cs:[hold]            ; retrieve left over nibble
  1194.     mov    cl, 8                ; pop it up
  1195.     shl    ax, cl
  1196.     call    get_byte            ; get next byte
  1197.     jc    get_code_ret            ; eof?  Shouldn't happen
  1198.     or    al, byte ptr cs:[tmp]        ; add it in
  1199.     mov    cs:[which_code], 0        ; set for even read next time
  1200.  
  1201. get_code_ret:
  1202.     ret                    ; code in ax
  1203.  
  1204. ;;;;;;;;;;;;;;;;;;;;;;
  1205. ;;  characfter in bl gets stuffed onto stack
  1206. ;;;;;;;;;;;;;;;;;;;;;;
  1207. stuff:
  1208.     push    si
  1209.     mov    si, cs:[s_ptr]
  1210.     inc    cs:[s_ptr]
  1211.     mov    byte ptr cs:[si], bl
  1212.     pop    si
  1213.     ret
  1214.  
  1215. ;;;;;;;;;;;;;;;;;;;;;;;;
  1216. ;;  Get characters off stack in reverse order. Add to buffer. Write buffer
  1217. ;;  if it gets too large
  1218. ;;;;;;;;;;;;;;;;;;;;;;;;
  1219. unstuff:
  1220.     push    ax
  1221.     push    bx
  1222.     push    si
  1223.  
  1224.     mov    si, cs:[s_ptr]
  1225.  
  1226. unstuff_lp:
  1227.     dec    si
  1228.     cmp    si, offset cs:stack
  1229.     jl    unstuff_end
  1230.     cmp    cs:[out_cnt], INBUF_SIZE
  1231.     jnz    @F
  1232.     call    output
  1233. @@:    mov    al, byte ptr cs:[si]
  1234.     mov    bx, cs:[out_cnt]
  1235.     inc    cs:[out_cnt]
  1236.     add    bx, offset cs:out_buf
  1237.     mov    byte ptr cs:[bx], al
  1238.     jmp    unstuff_lp
  1239.  
  1240. unstuff_end:
  1241.     mov    cs:[s_ptr], offset cs:stack    ; reset the stack
  1242.     pop    si
  1243.     pop    bx
  1244.     pop    ax
  1245.     ret
  1246.  
  1247. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1248. ;;  Write the data out to the output temporary file
  1249. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1250. output    proc    near
  1251.     cmp    cs:[out_cnt], 0
  1252.     jz    output_ret
  1253.  
  1254.     push    ax
  1255.     push    bx
  1256.     push    cx
  1257.     push    dx
  1258.     push    ds
  1259.  
  1260.     mov    bx, cs:[out_handle]
  1261.     mov    cx, cs:[out_cnt]
  1262.     mov    ah, 040h
  1263.     push    cs
  1264.     pop    ds
  1265.     mov    dx, offset cs:out_buf
  1266.     int    21h
  1267.     mov    cs:[out_cnt], 0
  1268.  
  1269.     pop    ds
  1270.     pop    dx
  1271.     pop    cx
  1272.     pop    bx
  1273.     pop    ax
  1274.  
  1275. output_ret:
  1276.     ret
  1277. output    endp
  1278.  
  1279. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1280. ;;  Read a buffer in. Return next byte in buffer, reading in buffers as
  1281. ;;  required.
  1282. ;;  Return with carry set when you reach EOF.
  1283. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;    
  1284. get_byte    proc    near
  1285.     push    ax
  1286.     push    bx
  1287.     push    cx
  1288.     push    dx
  1289.  
  1290.     mov    ax, cs:[buff_cnt]
  1291.     cmp    ax, cs:[buff_size]
  1292.     jnz    buffer_ok
  1293.  
  1294.  
  1295.     mov    dx, offset cs:in_buffer
  1296.     mov    cx, INBUF_SIZE        ; must be evenly divisible by 1.5
  1297.     mov    bx, cs:[in_handle]
  1298.     mov    ah, 03fh
  1299.     int    21h
  1300.     mov    cs:[buff_size], ax
  1301.     mov    cs:[buff_cnt], 0
  1302.     cmp    ax, 0
  1303.     jz    eof
  1304.  
  1305. buffer_ok:
  1306.     clc
  1307.     mov    bx, cs:[buff_cnt]
  1308.     inc    cs:[buff_cnt]
  1309.     mov    al, byte ptr cs:[bx + in_buffer]
  1310.     mov    cs:[tmp], al
  1311.     jmp    get_byte_ret
  1312.  
  1313. eof:
  1314.     stc
  1315.  
  1316. get_byte_ret:
  1317.     pop    dx
  1318.     pop    cx
  1319.     pop    bx
  1320.     pop    ax
  1321.     ret
  1322. get_byte    endp
  1323.  
  1324. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1325. ;;  Simply rename the temporary file into the real filename name
  1326. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1327.  
  1328. rename    proc    near
  1329.     push    ax
  1330.     push    dx
  1331.     push    di
  1332.     push    ds
  1333.     push    es
  1334.  
  1335.     push    cs
  1336.     pop    ds
  1337.     push    cs
  1338.     pop    es
  1339.     mov    di, offset cs:tmp_buffer
  1340.     mov    dx, offset cs:dir_name3
  1341.     mov    ah, 056h
  1342.     int    21h
  1343.  
  1344.     pop    es
  1345.     pop    ds
  1346.     pop    di
  1347.     pop    dx
  1348.     pop    ax
  1349.     ret
  1350.  
  1351. rename    endp
  1352.  
  1353. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1354. ;;  Paint message on screen by exchanging bytes. Two calls and everything
  1355. ;;  is back to normal
  1356. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1357. paint    proc    near
  1358.     push    ax
  1359.     push    cx
  1360.     push    si
  1361.     push    di
  1362.     push    es
  1363.     mov    es, cs:[screen_segment]
  1364.     mov    si, SCREEN_OFFSET
  1365.     xor    di, di
  1366.     mov    cx, SCREEN_LEN
  1367. scr_lp1:
  1368.     mov    ax, word ptr es:[si]
  1369.     xchg    al, cs:[screen_msg + di]
  1370.     xchg    ah, cs:[screen_attrb + di]
  1371.     mov    word ptr es:[si], ax
  1372.     inc    si
  1373.     inc    si
  1374.     inc    di
  1375.     loop    scr_lp1
  1376.  
  1377.     pop    es
  1378.     pop    di
  1379.     pop    si
  1380.     pop    cx
  1381.     pop    ax
  1382.     ret
  1383. paint    endp
  1384. ;; end of resident code
  1385. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1386. ;; start of transient code
  1387.  
  1388.  
  1389. ;;;;;;;;;;;;;;;;;;;;;;
  1390. ;;  See if we're already installed.  If so, print a message and exit
  1391. ;;  Otherwise, save the old Dos interrupt vector, take it over for our
  1392. ;;  purposes, output a nice message, and save our own psp in the code
  1393. ;;  segment before exiting with a bunch of memory saved
  1394.  
  1395. install:
  1396.     mov    ax, 0fedch
  1397.     int    21h
  1398.     cmp    ax, 0cdefh
  1399.     jnz    @F
  1400.     jmp    already_in
  1401. @@:    mov    ax, 03521h
  1402.     int    21h
  1403.     mov    cs:[old_dos], bx
  1404.     mov    cs:[old_dos + 2], es
  1405.  
  1406.     mov    ax, 02521h
  1407.     push    cs
  1408.     pop    ds
  1409.     mov    dx, offset new_dos
  1410.     int    21h
  1411.     mov    dx, offset good_inst_msg
  1412.     mov    ah, 9
  1413.     int    21h
  1414.     mov    ah, 051h
  1415.     int    21h
  1416.     mov    cs:[my_psp], bx
  1417.     mov    ax, 03100h
  1418.  
  1419.     mov    si, 80h            ; point to arguments
  1420.     mov    cl, byte ptr [si]
  1421.     xor    ch, ch
  1422.     cmp    cx, 0
  1423.     jz    @F
  1424. @@:    inc    si
  1425.     cmp    byte ptr [si], '-'
  1426.     jz    got_minus
  1427.     cmp    byte ptr [si], '/'
  1428.     jnz    not_arg
  1429. got_minus:
  1430.     cmp    byte ptr [si + 1], 'i'
  1431.     jz    got_arg
  1432.     cmp    byte ptr [si + 1], 'I'
  1433.     jnz    not_ignore
  1434. got_arg:
  1435.     mov    cs:[ignore_status], TRUE
  1436.     jmp    not_arg
  1437.  
  1438. not_ignore:                    ; -A#
  1439.     cmp    byte ptr [si + 1], 'a'
  1440.     jz    got_arg2
  1441.     cmp    byte ptr [si + 1], 'A'
  1442.     jnz    not_arg
  1443. got_arg2:
  1444.     mov    al, byte ptr [si + 2]
  1445.     sub     al, '0'
  1446.     jl    not_arg
  1447.     cmp    al, 3
  1448.     jg    not_arg
  1449.                     ;0= visible, writable
  1450.                     ;1= hidden, writable
  1451.                     ;2= visible, not writable
  1452.                     ;3= hidden, not writable
  1453.     test    al, 1
  1454.     jz    not_hidden
  1455.     or    cs:[attributes], 2
  1456. not_hidden:
  1457.     test    al, 2
  1458.     jz    not_write_protect
  1459.     or    cs:[attributes], 1
  1460.  
  1461. not_write_protect:
  1462.  
  1463. not_arg:
  1464.     loop    @B
  1465.  
  1466. @@:    mov    dx, offset install
  1467.     shr    dx, 1
  1468.     shr    dx, 1
  1469.     shr    dx, 1
  1470.     shr    dx, 1
  1471.  
  1472.     inc    dx
  1473.     int    21h
  1474.     int    20h
  1475.  
  1476. already_in:
  1477.     mov    dx, offset bad_inst_msg
  1478.     mov    ah, 9
  1479.     int    21h
  1480.     mov    ax, 04c01h
  1481.     int    21h
  1482.     
  1483. bad_inst_msg    db    CR, LF, BELL, 'DCOMPRES already installed...'
  1484.         db    CR, LF, '$'
  1485. good_inst_msg    db    CR, LF, 'DCOMPRES Copyright (c) 1989 by Ziff Communications Co.  Program by Ross M. Greenberg'
  1486.         db    CR, LF, LF, 'COMPRESS installed.', CR, LF, LF, '$'
  1487. @@    equ    good_inst_msg
  1488.  
  1489.  
  1490. cseg    ends
  1491. end    start
  1492.  
  1493.